package com.base.test.rabbitmq.config;

import com.base.test.rabbitmq.properties.Rabbit1Properties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.amqp.RabbitProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.interceptor.RetryInterceptorBuilder;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;

/**
 * RabbitMq 1配置类
 * @author qiaodong
 * @since 2020-04-09
 */
@Slf4j
@Configuration
@EnableConfigurationProperties(Rabbit1Properties.class)
@ConditionalOnProperty(value = "spring.rabbitmq.enable",havingValue = "true",matchIfMissing = true)
public class RabbitConfig {

    @Autowired
    private Rabbit1Properties rabbit1Properties;

    @Autowired
    RabbitProperties rabbitProperties;

    @Bean
    public ConnectionFactory firstConnectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses(rabbit1Properties.getHost()+":"+rabbit1Properties.getPort());
        connectionFactory.setUsername(rabbit1Properties.getUsername());
        connectionFactory.setPassword(rabbit1Properties.getPassword());
        connectionFactory.setVirtualHost(rabbit1Properties.getVirtualHost());
        /** 如果要进行消息回调，则这里必须要设置为true */
        connectionFactory.setPublisherConfirms(rabbit1Properties.isPublisherConfirms());
        connectionFactory.setConnectionTimeout(rabbit1Properties.getConnectionTimeout());
        connectionFactory.setCacheMode(CachingConnectionFactory.CacheMode.CHANNEL);
        connectionFactory.setChannelCacheSize(rabbit1Properties.getChannelCacheSize());
        return connectionFactory;
    }

    @Bean
    public SimpleRabbitListenerContainerFactory firstContainerFactory(
            @Qualifier("firstConnectionFactory") ConnectionFactory connectionFactory) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
        factory.setConnectionFactory(connectionFactory);
        factory.setAdviceChain(RetryInterceptorBuilder
                .stateless()
                .retryOperations(retryTemplate()).build());
        return factory;
    }

    @Bean
    @Scope("prototype")
    public RabbitTemplate firstRabbitTemplate() {
        RabbitTemplate template = new RabbitTemplate(firstConnectionFactory());
        template.setMandatory(rabbit1Properties.isTemplateMandatory());
        return template;
    }

    @Bean
    public RetryTemplate retryTemplate() {
        RetryTemplate retryTemplate = new RetryTemplate();
        retryTemplate.setBackOffPolicy(backOffPolicy());
        retryTemplate.setRetryPolicy(retryPolicy());
        return retryTemplate;
    }

    @Bean
    public ExponentialBackOffPolicy backOffPolicy(){
        ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
        long maxInterval = rabbitProperties.getListener().getSimple().getRetry().getMaxInterval().getSeconds();
        long initialInterval = rabbitProperties.getListener().getSimple().getRetry().getInitialInterval().getSeconds();
        double multiplier = rabbitProperties.getListener().getSimple().getRetry().getMultiplier();
        // 重试间隔
        backOffPolicy.setInitialInterval(initialInterval);
        // 重试最大间隔
        backOffPolicy.setMaxInterval(maxInterval);
        // 重试间隔乘法策略
        backOffPolicy.setMultiplier(multiplier);
        return backOffPolicy;
    }

    @Bean
    public SimpleRetryPolicy retryPolicy(){
        //设置重试异常和是否重试
        /*Map<Class<? extends Throwable>, Boolean> retryExceptions = new HashMap<>();
        retryExceptions.put(AmqpException.class, true);
        retryExceptions.put(Exception.class,true);
        retryExceptions.put(RuntimeException.class,true);
        retryExceptions.put(IOException.class,true);
        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(5,retryableExceptions);*/
        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
        int maxAttempts = rabbitProperties.getListener().getSimple().getRetry().getMaxAttempts();
        retryPolicy.setMaxAttempts(maxAttempts);
        return retryPolicy;
    }
}
